/**
 * promise实现的两点关键：.then链式调用，值的管道传输（上一个promise的返回值会作为下一个promise的参数）
 * 首先实现链式调用的原理就是返回一个新的promise,为什么这里不是直接返回this，我觉得是跟值的传输有关系
 * 值的管道传输：需要对上一次callback的返回值进行判断。如果是正常值，直接resolve/reject，如果是promise或者带有.then方法的，就直接调用.then方法
 * 还有一些重要的点，就是API的实现
 * 
 */
//promise三种状态，不可逆，pending--->fulfilled/rejected
const STATUS_PENDING = "pending";
const STATUS_FULFILLED = "fulfilled";
const STATUS_REJECTED = "rejected";

const resolvePromise = (promise2, x, resolve, reject) => {
    //防止在promise里面返回同一个promise,造成循环引用的问题
    if (promise2 === x) {
        return reject(new TypeError("循环引用"));
    }
    //如果x是MyPromise，则调用then方法。这里我觉得可以通过判断x.then是否是个方法也可以。
    if (x instanceof MyPromise) {
        return x.then(resolve, reject)
    }
    //x就是一个普通值
    return resolve(x);
}

class MyPromise {
    constructor(executor) {
        //构造函数的参数会立即同步被执行
        //初始化状态为pending，value用来存储resolve的值，reason用来存储reject的值，初始化都为undefined
        this.status = STATUS_PENDING;
        this.value = undefined;
        this.reason = undefined;
        this.onResolvedCallbacks = [];
        this.onRejectedCallbacks = [];
        let resolve = (value) => {
            if (this.status !== STATUS_PENDING) {
                return;
            }
            this.status = STATUS_FULFILLED;
            this.value = value;
            while (this.onResolvedCallbacks.length) {
                this.onResolvedCallbacks.shift()();
            }
        }

        let reject = (reason) => {
            if (this.status !== STATUS_PENDING) {
                return;
            }
            this.status = STATUS_REJECTED;
            this.reason = reason;
            while (this.onRejectedCallbacks.length) {
                this.onRejectedCallbacks.shift()();
            }
        }
        try {
            executor(resolve, reject);
        } catch (error) {
            this.reject(error);
        }
    }

    then(successCallback, failCallback) {
        //then支持链式调用，所以需要返回一个promise。通过返回一个新的promise实现数据的管道通信
        const promise2 = new MyPromise((resolve, reject) => {
            //resolve之后的执行的函数
            if (this.status === STATUS_FULFILLED) {
                //上次的promise的返回值，应该作为下一个promise的回调函数的参数
                //这里加上settimeout主要是拿到promise2，因为同步代码执行，拿不到promise2的值，所以加个异步，用来执行完同步代码之后，就可以拿到promise2的值
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);

            }
            //reject之后的执行的函数
            if (this.status === STATUS_REJECTED) {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);
            }
            //pending
            this.onResolvedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        let x = successCallback(this.value);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);
            });
            this.onRejectedCallbacks.push(() => {
                setTimeout(() => {
                    try {
                        let x = failCallback(this.reason);
                        resolvePromise(promise2, x, resolve, reject);
                    } catch (e) {
                        reject(e);
                    }

                }, 0);
            });
        });
        return promise2;

    }

    static resolve(value) {
        //resolve之后返回一个新的调用resolve的promise
        return new MyPromise((resolve) => {
            resolve(value);
        })
    }

    static reject(reason) {
        //reject之后返回一个新的调用reject的promise
        return new MyPromise((resolve, reject) => {
            reject(reason);
        })
    }

    static all(promises) {
        //所有的promise执行完了才会resolve，只要有一个有错，就会reject.而且返回的值是按照promises的顺序存储的
        return new MyPromise((resolve, reject) => {
            if (!Array.isArray(promises)) {
                return reject();
            }
            let result = [];
            let index = 0;
            promises.forEach((p, i) => {
                if (p instanceof MyPromise) {
                    p.then((value) => {
                        result[i] = value;
                        index++;
                        if (index === promises.length) {
                            resolve(result);
                        }
                    }, reject);
                } else {
                    result[i] = p;
                }
            });

        });

    }

    static race(promises) {
        //只要有一个成功了，就会resolve
        return new MyPromise((resolve, reject) => {
            promises.forEach(p => {
                p.then(resolve, reject);
            })
        });

    }
    catch(callback) {
        //catch其实就是一个没有successCallback的then
        return this.then(undefined, callback)
    }
    finally(callback) {
        //不管成功失败都会执行，并且返回promise的值
        return this.then(value => {
            return MyPromise.resolve(callback()).then(() => value);
        }, reason => {
            return MyPromise.resolve(callback()).then(() => { throw reason })
        })
    }
}

module.exports = MyPromise;